/**
 * @file      str.h
 * @copyright Copyright (c) 2020, ZCW Co., Ltd. All Rights Reserved.
 * @brief     brief
 * @author    caiwang213@qq.com
 * @date      2020-05-17 00:07:09
 *
 * @note
 *  str.h defines
 */
#ifndef __STR_H__
#define __STR_H__
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;

namespace log4x
{
class str
{
public:
    static string         to_str(int);
    static string         to_str(uint32_t);

    static string         to_str(int64_t);
    static string         to_str(uint64_t);
    static string         to_str(double);

    static int            to_int(const string&);
    static uint32_t       to_int32(const string&);
    static uint64_t       to_int64(const string&);

    static double         to_float(const string&);

    static string         to_ipv4(uint32_t);
    static string         to_ipv6(uint32_t*);

    static string         to_hex(uint8_t  num, bool prefix = false);
    static string         to_hex(uint16_t num, bool prefix = false);
    static string         to_hex(uint32_t num, bool prefix = false);
    static string         hex_dump(const uint8_t data[], size_t size, int colnum, const string& delim = "");
    static int            to_bytes(const string& hex, uint8_t bytes[], size_t &size, const string& delim = "");

    static string         format(const char* fmt, ...);

    static int            read_from_file(const string& fpath, string& data);
    static int            write_to_file(const string& fpath, const string& data);

    static int            split(const string& in, const string& pattern, vector<string> &parts);
    static string         strerror();
    static string         gsub(const string& str, const string& pattern, const string& replace);

    static int            stricmp(const string& s1, const string& s2);
    static int            strnicmp(const string& s1, const string& s2, size_t n);

    static string       & trim(string& str);

    static string       & ltrim(string &str);
    static string       & rtrim(string &str);
    static string       & lrtrim(string &str);
};
}


extern "C++"
{
    /**
     * High reliability and high security functions, and compatible with Linux and windows
     * for windows impliemnt we use the vc12.0 functions which with prefix "_s'.
     */
    template <size_t _size>
    inline
    char* strcpy_(char(&dest)[_size], const char* src)
    {
        if (_size <= strlen(src))
        {
            throw std::overflow_error("overflow_error");
        }

        ::strncpy(dest, src, strlen(src));
        dest[_size - 1] = '\0';

        return dest;
    }

    template <size_t _size>
    inline
    char* strncpy_(char(&dest)[_size], const char* src, size_t n)
    {
        /* ASSERT(!(_size < n && n <= strlen(src))); */
        /* ASSERT(!(_size < n && n >= strlen(src))); */
        /* ASSERT(!(_size == strlen(src) && n >= strlen(src))); */
        /* ASSERT(!(_size == n && n < strlen(src))); */

        ::strncpy(dest, src, n);

        if (n < _size)
        {
            dest[n] = '\0';
        }
        else
        {
            dest[_size - 1] = '\0';
        }

        return dest;
    }

    template <size_t _size>
    inline
    int sprintf_(char(&dest)[_size], const char* format, ...)
    {
        va_list arg;
        int done;

        va_start(arg, format);

        done = ::vsprintf(dest, format, arg);
        va_end(arg);

#ifdef __linux
        /* ASSERT(_size > (size_t)done); */
#endif
        return done;
    }

    template <size_t _size>
    inline
    int snprintf_(char(&dest)[_size], size_t n, const char* format, ...)
    {
        va_list arg;
        int done;

        va_start(arg, format);

        /* note: The return value in vc12.0 is not the same as the Linux
         * if(_size == n && strlen(format) >= n), will return - 1 on vs2013
         * and the actual length of format on Linux
         */
        done = ::vsnprintf(dest, n, format, arg);
        va_end(arg);

        /* ASSERT(!(_size < n && n <= (size_t)done)); */
        /* ASSERT(!(_size < n && n >= (size_t)done)); */
        /* ASSERT(!(_size == done && n >= (size_t)done)); */
        /* ASSERT(!(_size == n && n < (size_t)done)); */
        return done;
    }
}

#define strncpy_s            strncpy_
#define snprintf_s           snprintf_
#define strcpy_s			 strcpy_

#ifdef _WIN32
#define strcasecmp           _stricmp
#define strncasecmp          _strnicmp
#if defined(_MSC_VER) && (_MSC_VER > 1700)
#define vsnprintf_s          _vsnprintf_s
#define snprintf             _snprintf
#else
/* for vc6.0 */
/* #define snprintf             _snprintf */
/* #define vsnprintf            _vsnprintf */
#endif

#else
#define sprintf_s            sprintf_
#define vsnprintf_s          ::vsnprintf
#endif

#endif
